// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.

cbuffer LightConstantBuffer : register( b1 )
{
    float4 vToLightW;   // vector towards light source, in world coordinates. w component not used.
};

cbuffer PSConstantBuffer : register( b2 )
{
    float4 centerNormal;
    float4 move;
    float speed;
    float overcast;
    float colorFactor; // < 1 to darken; > 1 to lighten

    float pad; // byte width must be a multiple of 16
}

Texture2D PerlinTexture : register( t0 );
SamplerState PerlinSampler : register( s0 );

struct sPSInput
{
    float4 pos : SV_POSITION;
    float3 norm : NORMAL;
    float2 tex : TEXCOORD0;
};

float4 CloudPixelShader( sPSInput input ) : SV_TARGET
{
    float angle = ( dot( input.norm, centerNormal.xyz ) );
    clip( angle - .997 );                 // Clip pixel if it's out of range.
    float alpha = ( angle - .997 ) * 333; // Convert to range 0..1

    float4 perlin = PerlinTexture.Sample( PerlinSampler,input.tex + speed*move.xy ) /  2;
    perlin += PerlinTexture.Sample( PerlinSampler, input.tex *  2 + speed*move.xy ) /  4;
    perlin += PerlinTexture.Sample( PerlinSampler, input.tex *  4 + speed*move.xy ) /  8;
    perlin += PerlinTexture.Sample( PerlinSampler, input.tex *  8 + speed*move.xy ) / 16;
    perlin += PerlinTexture.Sample( PerlinSampler, input.tex * 16 + speed*move.xy ) / 32;
    perlin += PerlinTexture.Sample( PerlinSampler, input.tex * 32 + speed*move.xy ) / 32;

    float4 result = pow( abs( perlin ), overcast ) * 2.0f;

    result.a *= alpha;
    result.rgb *= colorFactor;

    float intensity = saturate( dot( input.norm, vToLightW.xyz ) );

    intensity = 0.96f * intensity + 0.04f;                    // add a small ambient light contribution
    intensity = sqrt( intensity );                            // gamma correct the lighting term

    result.rgb *= intensity;                                  // apply lighting to color texture

    return result;
}
